using System;
using System.Collections.Generic;
using System.Text;
using Hermes.Framework;
using Hermes.Framework.FileSystem;
using Hermes.Framework.Implementation.File;
using Hermes.Framework.Implementation.Directory;

namespace Hermes.Framework.Implementation
{
    public class SimpleTransactionOperationAbstractFactory : ITransactableOperationAbstractFactory
    {
        protected IResourceManager resourceManager = null;

        protected INonTransactableFileSystemFactory fileSystemFactory = null;

        protected SimpleTransactionOperationFactory operationFactory = null;

        public SimpleTransactionOperationAbstractFactory()
        {
            this.operationFactory = new SimpleTransactionOperationFactory();
        }

        #region ITransactableOperationAbstractFactory Members

        IResourceManager ITransactableOperationAbstractFactory.ResourceManager
        {
            set
            {
                this.resourceManager = value;
                this.operationFactory.ResourceManager = value;
            }
        }

        Hermes.Framework.FileSystem.INonTransactableFileSystemFactory ITransactableOperationAbstractFactory.FileSystemFactory
        {
            set
            {
                this.fileSystemFactory = value;
                this.operationFactory.FileSystemFactory = value;
            }
        }

        protected void InitializeOperation(ITransactableOperation operation, INonTransactableFileSystem fileSystem)
        {
            operation.FileSystem = fileSystem;
            operation.ResourceManager = this.resourceManager;
        }

        protected T GetOpeationBySingleParameter<FileType, DirectoryType, T>(string fileName) 
            where FileType : ITransactableOperation
            where DirectoryType: ITransactableOperation
        {
            ITransactableOperation operation = null;
            INonTransactableFileSystem fileSystem = this.fileSystemFactory.GetFileSystem(fileName);

            if (fileSystem.Exists(fileName))
            {
                operation = this.operationFactory.GetOperation<FileType>(fileName);
            }
            else if (fileSystem.IsDirectory(fileName))
            {
                operation = this.operationFactory.GetOperation<DirectoryType>(fileName);
            }
            InitializeOperation(operation, fileSystem);

            return (T)operation;
        }

        protected T GetOperationByTwoParameters<FileType, DirectoryType, T>(string from, string to)
            where FileType : ITransactableOperation
            where DirectoryType : ITransactableOperation
        {
            ITransactableOperation operation = null;
            INonTransactableFileSystem fileSystem = this.fileSystemFactory.GetFileSystem(from, to);

            if (fileSystem.Exists(from))
            {
                operation = this.operationFactory.GetOperation<FileType>(from, to);
            }
            else if (fileSystem.IsDirectory(from))
            {
                operation = this.operationFactory.GetOperation<DirectoryType>(from, to);
            }
            else if (from.EndsWith("\\"))
            {
                operation = this.operationFactory.GetOperation<DirectoryType>(from, to);
            }
            else
            {
                operation = this.operationFactory.GetOperation<FileType>(from, to);
            }
            this.InitializeOperation(operation, fileSystem);

            return (T)operation;
        }

        ITransactableCreate ITransactableOperationAbstractFactory.GetCreate(string fileName)
        {
            return this.GetOpeationBySingleParameter<TxFileCreate, TxDirectoryCreate, ITransactableCreate>(fileName);
        }

        ITransactableCopy ITransactableOperationAbstractFactory.GetCopy(string from, string to)
        {
            return this.GetOperationByTwoParameters<TxFileCopy, TxDirectoryCopy, ITransactableCopy>(from, to);
        }

        ITransactableMove ITransactableOperationAbstractFactory.GetMove(string from, string to)
        {
            return this.GetOperationByTwoParameters<TxFileMove, TxDirectoryMove, ITransactableMove>(from, to);
        }

        ITransactableDelete ITransactableOperationAbstractFactory.GetDelete(string fileName)
        {
            return this.GetOpeationBySingleParameter<TxFileDelete, TxDirectoryDelete, ITransactableDelete>(fileName);
        }

        #endregion
    }
}
